package com.yb.livewykt.ui.model

import android.content.Context
import android.hardware.Camera
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.os.Message
import android.util.Log
import com.yb.livewykt.bean.*
import com.yb.livewykt.ui.inter.OnBundleLoadCompleteListener
import com.yb.livewykt.ui.inter.OnFUControlListener
import com.yb.livewykt.util.GlUtil
import java.io.IOException
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import com.faceunity.wrapper.faceunity


class FURendererKt(val context: Context, val isCreateEGLContext: Boolean) : OnFUControlListener {

    private val TAG = javaClass.simpleName


    //美颜和其他道具的handle数组
    private val mItemsArray = IntArray(ITEM_ARRAYS_COUNT)

    //用于和异步加载道具的线程交互
    private var mFuItemHandler: Handler? = null

    private var isNeedFaceBeauty = true
    private var isNeedBeautyHair = false
    private var isNeedAnimoji3D = false
    private var isNeedPosterFace = false
    private var isNeedBodySlim = false
    private var mDefaultEffect : Beauty? = null //默认道具
    private var mIsCreateEGLContext = false //是否需要手动创建EGLContext
    private var mInputTextureType = 0 //输入的图像texture类型，Camera提供的默认为EXTERNAL OES

    private var mInputImageFormat = 0

    @Volatile
    private var mIsNeedUpdateFaceBeauty = true
    private var mBodySlimStrength = 0.0f // 瘦身

    private var mLegSlimStrength = 0.0f // 长腿

    private var mWaistSlimStrength = 0.0f // 细腰

    private var mShoulderSlimStrength = 0.5f // 美肩

    private var mHipSlimStrength = 0.0f // 美胯

    private var mHeadSlimStrength = 0.0f // 小头

    private var mLegThinSlimStrength = 0.0f // 瘦腿


    private var mInputOrientation = 270
    private var mExternalInputType = EXTERNAL_INPUT_TYPE_NONE
    private var mIsSystemCameraRecord = false
    private var mCameraFacing = Camera.CameraInfo.CAMERA_FACING_FRONT
    private var mMaxFaces = 4 // 同时识别的最大人脸数

    private var mMaxHumans = 1 // 同时识别的最大人体数

    // 美发参数
    private var mHairColorStrength = 0.6f
    private var mHairColorType = HAIR_GRADIENT
    private var mHairColorIndex = 0

    // 美妆妆容参数集合
    private val mMakeupParams: MutableMap<String, Any> = ConcurrentHashMap(16)

    // 轻美妆妆容集合，保证预定义的子妆容顺序，口红要最后上妆，这样才不会被覆盖
    private val mLightMakeupItemMap: MutableMap<Int, LightMakeupItem> = LinkedHashMap(16)

    // 美妆组合妆
    private var mMakeupEntity: MakeupEntity? = null

    // 美妆子妆句柄集合
    private val mMakeupItemHandleMap: MutableMap<String, Int> = HashMap(16)

    // 美妆点位是否镜像
    private var mIsMakeupFlipPoints = false

    private val rotationData = FloatArray(4)
    private val faceRectData = FloatArray(4)

    private var mEventQueue: MutableList<Runnable>? = null
    private var mGlThreadId: Long = 0
    private var mOnBundleLoadCompleteListener: OnBundleLoadCompleteListener? =
        null
    private var mCartoonFilterStyle: Int = CartoonFilterParam.NO_FILTER

    /* 设备方向 */
    @Volatile
    private var mDeviceOrientation = 90

    /* 人脸识别方向 */
    @Volatile
    private var mRotationMode = faceunity.FU_ROTATION_MODE_90

    private var mIsLoadAiGesture = false
    private var mIsLoadAiHumanProcessor = false

    companion object{
        const val FU_ADM_FLAG_EXTERNAL_OES_TEXTURE:Int = faceunity.FU_ADM_FLAG_EXTERNAL_OES_TEXTURE
        /**
         * 外部输入类型
         */
        const val EXTERNAL_INPUT_TYPE_NONE:Int = -1
        const val EXTERNAL_INPUT_TYPE_IMAGE:Int = 0
        const val EXTERNAL_INPUT_TYPE_VIDEO:Int = 1

        /*
        算法检测类型
         */
        const val TRACK_TYPE_FACE:Int = faceunity.FUAITYPE_FACEPROCESSOR
        const val TRACK_TYPE_HUMAN:Int = faceunity.FUAITYPE_HUMAN_PROCESSOR
        const val TRACK_TYPE_GESTURE:Int = faceunity.FUAITYPE_HANDGESTURE

        //图形道具文件夹
        const val GRAPHICS_ASSETS_DIR = "graphics/"
        const val BUNDLE_FXAA = GRAPHICS_ASSETS_DIR + "fxaa.bundle"
        const val BUNDLE_FACE_BEAUTIFICATION = GRAPHICS_ASSETS_DIR + "face_beautification.bundle"
        const val BUNDLE_HAIR_NORMAL = "effect/hair_seg/hair_normal.bundle"
        const val BUNDLE_HAIR_GRADIENT = "effect/hair_seg/hair_gradient.bundle"
        const val BUNDLE_CHANGE_FACE = "change_face/change_face.bundle"
        const val BUNDLE_CARTOON_FILTER = GRAPHICS_ASSETS_DIR + "fuzzytoonfilter.bundle"
        const val BUNDLE_LIGHT_MAKEUP = "light_makeup/light_makeup.bundle"
        const val BUNDLE_FACE_MAKEUP = GRAPHICS_ASSETS_DIR + "face_makeup.bundle";
        const val BUNDLE_BEAUTIFY_BODY = GRAPHICS_ASSETS_DIR + "body_slim.bundle";
        const val AI_MODEL_ASSETS_DIR = "model/";
        const val BUNDLE_AI_MODEL_FACE_PROCESSOR = AI_MODEL_ASSETS_DIR + "ai_face_processor.bundle";
        const val BUNDLE_TONGUE = GRAPHICS_ASSETS_DIR + "tongue.bundle";
        const val LANDMARKS = "landmarks";

        private var sIsBeautyOn = 1.0f
        private var sFilterName: String = BeautificationParam.MITAO_1 // 滤镜：自然 2

        private var mFilterLevel = 0.4f //滤镜强度

        private var mBlurLevel = 0.7f //磨皮程度

        private var mBlurType = 2.0f //磨皮类型：精细磨皮

        private var mColorLevel = 0.3f //美白

        private var mRedLevel = 0.3f //红润

        private var mEyeBright = 0.0f //亮眼

        private var mToothWhiten = 0.0f //美牙

        private var mFaceShape = 4f //脸型：精细变形

        private var mFaceShapeLevel = 1.0f //变形程度

        private var mCheekThinning = 0f //瘦脸

        private var mCheekV = 0.5f //V脸

        private var mCheekNarrow = 0f //窄脸

        private var mCheekSmall = 0f //小脸

        private var mEyeEnlarging = 0.4f //大眼

        private var mIntensityChin = 0.3f //下巴

        private var mIntensityForehead = 0.3f //额头

        private var mIntensityMouth = 0.4f //嘴形

        private var mIntensityNose = 0.5f //瘦鼻

        private var sMicroPouch = 0f // 去黑眼圈

        private var sMicroNasolabialFolds = 0f // 去法令纹

        private var sMicroSmile = 0f // 微笑嘴角

        private var sMicroCanthus = 0f // 眼角

        private var sMicroPhiltrum = 0.5f // 人中

        private var sMicroLongNose = 0.5f // 鼻子长度

        private var sMicroEyeSpace = 0.5f // 眼睛间距

        private var sMicroEyeRotate = 0.5f // 眼睛角度

        private var mFrameId:Int = 0

        // 句柄索引
        private const val ITEM_ARRAYS_FACE_BEAUTY_INDEX = 0
        private const val ITEM_ARRAYS_EFFECT_INDEX = 1
        private const val ITEM_ARRAYS_LIGHT_MAKEUP_INDEX = 2
        private const val ITEM_ARRAYS_ABIMOJI_3D_INDEX = 3
        private const val ITEM_ARRAYS_BEAUTY_HAIR_INDEX = 4
        private const val ITEM_ARRAYS_CHANGE_FACE_INDEX = 5
        private const val ITEM_ARRAYS_CARTOON_FILTER_INDEX = 6
        private const val ITEM_ARRAYS_FACE_MAKEUP_INDEX = 7
        private const val ITEM_ARRAYS_BEAUTIFY_BODY = 10

        // 句柄数量
        private const val ITEM_ARRAYS_COUNT = 11

        // 海报换脸 track face 50 次，确保检测成功率
        private const val MAX_TRACK_COUNT = 50

        // 美发类型
        var HAIR_NORMAL = 0
        var HAIR_GRADIENT = 1
        private var sIsInited = false
        fun initFURenderer(context: Context){
            if (sIsInited){
                return
            }

            faceunity.fuSetLogLevel(6)
            faceunity.fuHexagonInitWithPath(context.applicationInfo.nativeLibraryDir)
            faceunity.fuSetup(ByteArray(0), authpack.A())
            loadAiModel(context, BUNDLE_AI_MODEL_FACE_PROCESSOR, faceunity.FUAITYPE_FACEPROCESSOR)
            loadTongueModel(context, BUNDLE_TONGUE)
            sIsInited = isLibInit()
        }
        private fun loadAiModel(context: Context, bundlePath: String, type: Int){
            val buffer = readFile(context, bundlePath)
            faceunity.fuLoadAIModelFromPackage(buffer, type)
        }
        private fun loadTongueModel(context: Context, bundlePath: String){
            val buffer = readFile(context, bundlePath)
            faceunity.fuLoadTongueModel(buffer)
        }
        private fun isLibInit() : Boolean = faceunity.fuIsLibraryInit() == 1

        private fun readFile(context: Context, bundlePath: String?) : ByteArray?{
            if (bundlePath.isNullOrEmpty()) return null
            return try {
                val inputStream = context.assets.open(bundlePath)
                var buffer = ByteArray(inputStream.available())
                inputStream.read(buffer)
                inputStream.close()
                buffer
            }catch (e: IOException){
                e.printStackTrace()
                null
            }
        }

        fun destroyLibData(){
            releaseAiModel(faceunity.FUAITYPE_FACEPROCESSOR)
            if (sIsInited){
                faceunity.fuDestroyLibData()
                sIsInited = isLibInit()
            }
        }
        private fun releaseAiModel(type: Int){
            if (faceunity.fuIsAIModelLoaded(type) == 1) faceunity.fuReleaseAIModel(type)
        }
        private fun releaseAllAiModel(){
            releaseAiModel(faceunity.FUAITYPE_BACKGROUNDSEGMENTATION)
            releaseAiModel(faceunity.FUAITYPE_HAIRSEGMENTATION)
            releaseAiModel(faceunity.FUAITYPE_HANDGESTURE)
            releaseAiModel(faceunity.FUAITYPE_HUMAN_PROCESSOR)
        }

        private fun loadItem(context: Context, bundlePath: String?) : Int{
            val buffer = readFile(context, bundlePath)
            return if (buffer != null){
                faceunity.fuCreateItemFromPackage(buffer)
            }else{
                0
            }
        }
    }

    fun onSurfaceCreated(){
        mEventQueue = Collections.synchronizedList(ArrayList<Runnable>(16))
        mGlThreadId = Thread.currentThread().id
        val handlerThread = HandlerThread("FUItemWorker")
        handlerThread.start()
        val fuItemHandler = FuItemHandler(handlerThread.looper)
        mFuItemHandler = fuItemHandler

        /**
         * fuCreateEGLContext 创建OpenGL环境
         * 适用于没OpenGL环境时调用
         * 如果调用了fuCreateEGLContext，在销毁时需要调用fuReleaseEGLContext
         */
        if (mIsCreateEGLContext){
            faceunity.fuCreateEGLContext()
        }
        mFrameId = 0
        setMaxFaces(mMaxFaces)
        val rotationMode = calculateRotationMode()
        faceunity.fuSetDefaultRotationMode(rotationMode)
        mRotationMode = rotationMode

        if (mIsLoadAiHumanProcessor){
            fuItemHandler.post{
                loadAiModel(
                    context,
                    "$AI_MODEL_ASSETS_DIR+ai_human_processor.bundle",
                    faceunity.FUAITYPE_FACEPROCESSOR
                )
                setMaxHumans(mMaxHumans)
            }
        }
        if (mIsLoadAiGesture){
            fuItemHandler.post{
                loadAiModel(
                    context,
                    "$AI_MODEL_ASSETS_DIR+ai_gesture.bundle",
                    faceunity.FUAITYPE_HANDGESTURE
                )
            }
        }
        if (isNeedFaceBeauty){
            fuItemHandler.sendEmptyMessage(ITEM_ARRAYS_FACE_BEAUTY_INDEX)
        }
        if (isNeedBeautyHair){
            fuItemHandler.sendEmptyMessage(ITEM_ARRAYS_BEAUTY_HAIR_INDEX)
        }
        if (isNeedAnimoji3D){
            fuItemHandler.sendEmptyMessage(ITEM_ARRAYS_ABIMOJI_3D_INDEX)
        }
        if (isNeedBodySlim){
            fuItemHandler.sendEmptyMessage(ITEM_ARRAYS_BEAUTIFY_BODY)
        }
        if (isNeedPosterFace){
            mItemsArray[ITEM_ARRAYS_CHANGE_FACE_INDEX] = loadItem(context, BUNDLE_CHANGE_FACE)
        }

        val cartoonFilterStyle = mCartoonFilterStyle
        mCartoonFilterStyle = CartoonFilterParam.NO_FILTER
        setCartoonFilter(cartoonFilterStyle)

        //异步加载默认道具
        Message.obtain(fuItemHandler, ITEM_ARRAYS_EFFECT_INDEX, mDefaultEffect).sendToTarget()

        if (mMakeupEntity!=null)
            Message.obtain(
                fuItemHandler,
                ITEM_ARRAYS_FACE_MAKEUP_INDEX,
                MakeupEntity(mMakeupEntity!!)
            ).sendToTarget()
        if (mLightMakeupItemMap.isNotEmpty()){
            val makeupItems = mLightMakeupItemMap.values
            onLightMakeupCombinationSelected(ArrayList<LightMakeupItem>(makeupItems))
        }
    }


    /**
    * 双输入api，处理后的画面数据并不会写到数组里面 ，推荐使用
     */
    fun onDrawFrame(img: ByteArray, tex: Int, w: Int, h: Int) : Int{
        if (tex <= 0 || img == null || w <= 0 || h <= 0){
            return 0
        }
        prepareDrawFrame()


        var flags = mInputTextureType or mInputImageFormat
        if (mCameraFacing != Camera.CameraInfo.CAMERA_FACING_FRONT)
            flags = flags or faceunity.FU_ADM_FLAG_FLIP_X
        if (mNeedBenchmark) mFuCallStartTime = System.nanoTime()
        val fuTex = faceunity.fuDualInputToTexture(img, tex, flags, w, h, mFrameId++, mItemsArray)
        if (mNeedBenchmark) mOneHundredFrameFUTime += System.nanoTime() - mFuCallStartTime
        return fuTex
    }

    /**
     * 每帧画面处理时被调用
     *
     */
    private fun prepareDrawFrame() {
        benchmarkFPS()


        if (mIsLoadAiHumanProcessor){


            val trackHumans = faceunity.fuHumanProcessorGetNumResults()
            if (mTrackHumanStatus != trackHumans){
                mTrackHumanStatus = trackHumans
                onTrackingStatusChangeListener?.onTrackStatusCHanged(TRACK_TYPE_HUMAN, trackHumans)
            }
        }else{
            val trackFace = faceunity.fuIsTracking()
            if (mTrackFaceStatus != trackFace){
                mTrackFaceStatus = trackFace
                onTrackingStatusChangeListener?.onTrackStatusCHanged(TRACK_TYPE_FACE, trackFace)
            }
        }


        // 获取 SDK 错误信息，并调用回调接口
        val error = faceunity.fuGetSystemError()
        if (error != 1) {
            val errorMessage = faceunity.fuGetSystemErrorString(error)
            Log.d(TAG, "prepareDrawFrame: $error \t $errorMessage")
            mOnSystemErrorListener?.onSystemError(errorMessage)
        }

        //修改美颜参数
        if (mIsNeedUpdateFaceBeauty && mItemsArray[ITEM_ARRAYS_FACE_BEAUTY_INDEX] > 0){
            val itemFaceBeauty = mItemsArray[ITEM_ARRAYS_FACE_BEAUTY_INDEX]
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.IS_BEAUTY_ON,
                sIsBeautyOn.toDouble()
            )
            Log.d(TAG, "prepareDrawFrame: $sFilterName \t $mFilterLevel")
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.FILTER_NAME,
                sFilterName
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.FILTER_LEVEL,
                mFilterLevel.toDouble()
            )

            faceunity.fuItemSetParam(itemFaceBeauty, BeautificationParam.HEAVY_BLUR, 0.0)
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.BLUR_TYPE,
                mBlurType.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.BLUR_LEVEL,
                6.0 * mBlurLevel.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.COLOR_LEVEL,
                mColorLevel.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.RED_LEVEL,
                mRedLevel.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.EYE_BRIGHT,
                mEyeBright.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.TOOTH_WHITEN,
                mToothWhiten.toDouble()
            )

            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.FACE_SHAPE_LEVEL,
                mFaceShapeLevel.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.FACE_SHAPE,
                mFaceShape.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.EYE_ENLARGING,
                mEyeEnlarging.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.CHEEK_THINNING,
                mCheekThinning.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.CHEEK_NARROW,
                mCheekNarrow.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.CHEEK_SMALL,
                mCheekSmall.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.CHEEK_V,
                mCheekV.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_NOSE,
                mIntensityNose.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_CHIN,
                mIntensityChin.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_FOREHEAD,
                mIntensityForehead.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_MOUTH,
                mIntensityMouth.toDouble()
            )

            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.REMOVE_POUCH_STRENGTH,
                sMicroPouch.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.REMOVE_NASOLABIAL_FOLDS_STRENGTH,
                sMicroNasolabialFolds.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_SMILE,
                sMicroSmile.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_CANTHUS,
                sMicroCanthus.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_PHILTRUM,
                sMicroPhiltrum.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_LONG_NOSE,
                sMicroLongNose.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_EYE_SPACE,
                sMicroEyeSpace.toDouble()
            )
            faceunity.fuItemSetParam(
                itemFaceBeauty,
                BeautificationParam.INTENSITY_EYE_ROTATE,
                sMicroEyeRotate.toDouble()
            )

            mIsNeedUpdateFaceBeauty = false
        }

        while (!mEventQueue.isNullOrEmpty()){
            mEventQueue?.removeAt(0)?.run()
        }
    }

    fun cameraChanged(){
        queueEvent(Thread {
            mFrameId = 0
            faceunity.fuOnCameraChange()
        })
    }



    fun onSurfaceDestroyed(){
        mFuItemHandler?.removeCallbacksAndMessages(null)
        mFuItemHandler?.looper?.quit()

        mEventQueue?.clear()

        mGlThreadId = 0

        if (mItemsArray.size > PTA_BIND_ITEM_COUNT){
            val posterIndex = mItemsArray[ITEM_ARRAYS_CHANGE_FACE_INDEX]
            if (posterIndex > 0){
                faceunity.fuDeleteTexForItem(posterIndex, "tex_input")
                faceunity.fuDeleteTexForItem(posterIndex, "tex_template")
            }

            val lightMakeupIndex = mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX]
            if (lightMakeupIndex > 0){
                mLightMakeupItemMap.forEach {
                    faceunity.fuDeleteTexForItem(
                        lightMakeupIndex, MakeupParamHelper.getMakeupTextureKeyByType(
                            it.key
                        )
                    )
                }
            }
            val faceMakeupIndex = mItemsArray[ITEM_ARRAYS_FACE_MAKEUP_INDEX]
            if (faceMakeupIndex > 0){
                if (mMakeupEntity != null && mMakeupEntity!!.itemHandle >0){
                    faceunity.fuUnBindItems(
                        faceMakeupIndex,
                        intArrayOf(mMakeupEntity!!.itemHandle)
                    )
                    faceunity.fuDestroyItem(mMakeupEntity!!.itemHandle)
                    mMakeupEntity!!.itemHandle = 0
                }
                if (mMakeupItemHandleMap.isNotEmpty()){
                    faceunity.fuUnBindItems(
                        faceMakeupIndex,
                        mMakeupItemHandleMap.values.toIntArray()
                    )
                    mMakeupItemHandleMap.forEach {
                        faceunity.fuDestroyItem(it.value)
                    }
                    mMakeupItemHandleMap.clear()
                }
            }
        }

        mFrameId = 0
        mIsNeedUpdateFaceBeauty = true
        releaseAllAiModel()
        destroyControllerRelated()
        mItemsArray.forEach {
            if (it>0) faceunity.fuDestroyItem(it)
        }
        Arrays.fill(mItemsArray, 0)
        faceunity.fuOnCameraChange()
        faceunity.fuDestroyAllItems()
        faceunity.fuOnDeviceLost()
        faceunity.fuDone()
        if (mIsCreateEGLContext){
            faceunity.fuReleaseEGLContext()
        }
    }


    //************************PTA 相关功能
    //************************** PTA 相关功能 ******************************
    private val PTA_ASSETS_DIR: String? = "pta/"
    private val PTA_BOY_DIR = "boy/"
    private val PTA_GIRL_DIR = "girl/"
    private val PTA_BOY_BUNDLES = arrayOf(
        "head.bundle", "midBody_male.bundle",
        "male_hair_5.bundle", "toushi_7.bundle", "peishi_erding_2.bundle", "waitao_3.bundle",
        "kuzi_changku_5.bundle", "xiezi_tuoxie_2.bundle"
    )
    private val PTA_GIRL_BUNDLES = arrayOf(
        "head.bundle", "midBody_female.bundle",
        "female_hair_23.bundle", "toushi_5.bundle", "taozhuang_12.bundle", "facemakeup_3.bundle",
        "xiezi_danxie.bundle"
    )
    private val GESTURE_BIND_BUNDLES = arrayOf(
        "anim_idle.bundle",
        "anim_eight.bundle",
        "anim_fist.bundle",
        "anim_greet.bundle",
        "anim_gun.bundle",
        "anim_heart.bundle",
        "anim_hold.bundle",
        "anim_korheart.bundle",
        "anim_merge.bundle",
        "anim_ok.bundle",
        "anim_one.bundle",
        "anim_palm.bundle",
        "anim_rock.bundle",
        "anim_six.bundle",
        "anim_thumb.bundle",
        "anim_two.bundle"
    )
    private val PTA_BIND_ITEM_COUNT = 2 // PTA 默认绑定两项：config 和 bg

    private val PTA_ITEM_COUNT = 2
    private val PTA_ALWAYS_BIND_ITEM_COUNT =
        PTA_BIND_ITEM_COUNT + GESTURE_BIND_BUNDLES.size // PTA 始终绑定的 config、bg、anim

    /**
     * 人体跟踪模式，全身或者半身
     */
    val HUMAN_TRACK_SCENE_FULL = 1
    val HUMAN_TRACK_SCENE_HALF = 0
    //private val mRotatedImage = RotatedImage()
    private val mControllerBoundItems: IntArray = IntArray(0)
    private val mHumanTrackScene = HUMAN_TRACK_SCENE_FULL


    private fun destroyControllerRelated(){
        if (mControllerBoundItems != null && mControllerBoundItems[0] >0){
            val controllerItem = mItemsArray[0]
            faceunity.fuItemSetParam(controllerItem, "quit_human_pose_track_mode", 1.0)
            val controllerBoundItems = validateItems(mControllerBoundItems)
            faceunity.fuUnBindItems(controllerItem, controllerBoundItems)
            controllerBoundItems.forEach {
                faceunity.fuDestroyItem(it)
            }
            Arrays.fill(controllerBoundItems, 0)
        }
    }

     private fun validateItems(intArray: IntArray) : IntArray{
         var output = IntArray(intArray.size)
         var count = 0
         intArray.forEach {
             if (it>0) output[count++] = it
         }
         return output.copyOfRange(0, count)
     }



    // -------------------对外可以使用的APi

    /**
     * 设置识别的人脸数
     */

    fun setMaxFaces(maxFace: Int){
        if (maxFace > 0){
            mMaxFaces = maxFace
            queueEvent(Thread {
                faceunity.fuSetMaxFaces(maxFace)
            })
        }
    }
    fun queueEvent(runnable: Runnable){
        if (Thread.currentThread().id == mGlThreadId){
            runnable.run()
        }else{
            mEventQueue?.add(runnable)
        }
    }

    /**
     * 设置需要识别的人体个数
     */
    fun setMaxHumans(maxHumans: Int){
        if (maxHumans > 0){
            mMaxHumans = maxHumans
            queueEvent(Thread {
                faceunity.fuHumanProcessorSetMaxHumans(maxHumans)
            })
        }
    }

    private fun calculateRotationMode() : Int{
        return when(mExternalInputType){
            EXTERNAL_INPUT_TYPE_IMAGE -> {
                faceunity.FU_ROTATION_MODE_0
            }
            EXTERNAL_INPUT_TYPE_VIDEO -> {
                when (mInputOrientation) {
                    90 -> {
                        faceunity.FU_ROTATION_MODE_270
                    }
                    270 -> {
                        faceunity.FU_ROTATION_MODE_90
                    }
                    else -> {
                        faceunity.FU_ROTATION_MODE_0
                    }
                }
            }
            else ->{
                var rotModel = faceunity.FU_ROTATION_MODE_0
                when(mInputOrientation){
                    270 -> {
                        rotModel = if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                            mDeviceOrientation.div(90)
                        } else {
                            when (mDeviceOrientation) {
                                180 -> {
                                    faceunity.FU_ROTATION_MODE_0
                                }
                                0 -> {
                                    faceunity.FU_ROTATION_MODE_180
                                }
                                else -> {
                                    mDeviceOrientation.div(90)
                                }
                            }
                        }
                    }
                    90 -> {
                        rotModel = if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                            when (mDeviceOrientation) {
                                90 -> faceunity.FU_ROTATION_MODE_270
                                270 -> faceunity.FU_ROTATION_MODE_90
                                else -> mDeviceOrientation.div(90)
                            }
                        } else {
                            when (mDeviceOrientation) {
                                0 -> faceunity.FU_ROTATION_MODE_180
                                90 -> faceunity.FU_ROTATION_MODE_270
                                180 -> faceunity.FU_ROTATION_MODE_0
                                else -> faceunity.FU_ROTATION_MODE_90
                            }
                        }
                    }
                }
                rotModel
            }
        }
    }







    override fun setBeautificationOn(isOn: Boolean) {
        val isBeautyOn = if (isOn) 1.0f else 0.0f
        if (sIsBeautyOn == isBeautyOn) {
            return
        }
        sIsBeautyOn = isBeautyOn
        queueEvent(Runnable {
            val itemFaceBeauty =
                mItemsArray[ITEM_ARRAYS_FACE_BEAUTY_INDEX]
            if (itemFaceBeauty > 0) {
                faceunity.fuItemSetParam(
                    itemFaceBeauty,
                    BeautificationParam.IS_BEAUTY_ON,
                    sIsBeautyOn.toDouble()
                )
            }
        })
    }

    override fun onMusicFilterTime(time: Long) {
        queueEvent(Runnable {
            val itemEffect = mItemsArray[ITEM_ARRAYS_EFFECT_INDEX]
            if (itemEffect > 0) {
                faceunity.fuItemSetParam(itemEffect, "music_time", time.toDouble())
            }
        })
    }

    override fun onEffectSelected(effect: Beauty) {
        if (effect == null || effect === mDefaultEffect) {
            return
        }
        mDefaultEffect = effect
        if (mFuItemHandler == null) {
            queueEvent(Runnable {
                mFuItemHandler!!.removeMessages(ITEM_ARRAYS_EFFECT_INDEX)
                mFuItemHandler!!.sendMessage(
                    Message.obtain(
                        mFuItemHandler,
                        ITEM_ARRAYS_EFFECT_INDEX,
                        mDefaultEffect
                    )
                )
            })
        } else {
            mFuItemHandler!!.removeMessages(ITEM_ARRAYS_EFFECT_INDEX)
            mFuItemHandler!!.sendMessage(
                Message.obtain(
                    mFuItemHandler,
                    ITEM_ARRAYS_EFFECT_INDEX,
                    mDefaultEffect
                )
            )
        }
    }

    override fun onFilterNameSelected(name: String) {
        sFilterName = name
        mIsNeedUpdateFaceBeauty = true
    }

    override fun onFilterLevelSelected(level: Float) {
        mFilterLevel = level
        mIsNeedUpdateFaceBeauty = true
    }

    override fun onHairSelected(type: Int, index: Int, strength: Float) {
        if (mHairColorType == type) {
            onHairStrengthSelected(index, strength)
        } else {
            mHairColorType = type
            mHairColorIndex = index
            mHairColorStrength = strength
            mFuItemHandler?.sendEmptyMessage(ITEM_ARRAYS_BEAUTY_HAIR_INDEX)
        }
    }

    override fun onHairStrengthSelected(index: Int, strength: Float) {
        mHairColorIndex = index
        mHairColorStrength = strength
        queueEvent(Runnable {
            val itemHair =
                mItemsArray[ITEM_ARRAYS_BEAUTY_HAIR_INDEX]
            if (itemHair > 0) {
                faceunity.fuItemSetParam(itemHair, HairParam.INDEX, mHairColorIndex.toDouble())
                faceunity.fuItemSetParam(
                    itemHair,
                    HairParam.STRENGTH,
                    mHairColorStrength.toDouble()
                )
            }
        })
    }

    override fun onBlurTypeSelected(type: Float) {
        mBlurType = type
        mIsNeedUpdateFaceBeauty = true
    }

    override fun onBlurLevelSelected(level: Float) {
        mBlurLevel = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onColorLevelSelected(level: Float) {
        mColorLevel = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onRedLevelSelected(level: Float) {
        mRedLevel = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onEyeBrightSelected(level: Float) {
        mEyeBright = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onToothWhitenSelected(level: Float) {
        mToothWhiten = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onEyeEnlargeSelected(level: Float) {
        mEyeEnlarging = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onCheekThinningSelected(level: Float) {
        mCheekThinning = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onIntensityChinSelected(level: Float) {
        mIntensityChin = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onIntensityForeheadSelected(level: Float) {
        mIntensityForehead = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onIntensityNoseSelected(level: Float) {
        mIntensityNose = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onIntensityMouthSelected(level: Float) {
        mIntensityMouth = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onCheekNarrowSelected(level: Float) {
        // 窄脸参数上限为0.5
        mCheekNarrow = level / 2;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onCheekSmallSelected(level: Float) {
        // 小脸参数上限为0.5
        mCheekSmall = level / 2;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onCheekVSelected(level: Float) {
        mCheekV = level;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun onPosterTemplateSelected(
        tempWidth: Int,
        tempHeight: Int,
        temp: ByteArray,
        landmark: FloatArray
    ) {
        val item = mItemsArray[ITEM_ARRAYS_CHANGE_FACE_INDEX];
        if (item > 0) {
            val landmarks = floatArrayToDouble(landmark);
            // 模板图片的宽
            faceunity.fuItemSetParam(item, "template_width", tempWidth.toDouble());
            // 模板图片的高
            faceunity.fuItemSetParam(item, "template_height", tempHeight.toDouble());
            // 图片的特征点，75个点
            faceunity.fuItemSetParam(item, "template_face_points", landmarks);
            // 模板图片的 RGBA byte数组
            faceunity.fuCreateTexForItem(item, "tex_template", temp, tempWidth, tempHeight);
        }
    }

    override fun onPosterInputPhoto(
        inputWidth: Int,
        inputHeight: Int,
        input: ByteArray,
        landmark: FloatArray
    ) {
        val item = mItemsArray[ITEM_ARRAYS_CHANGE_FACE_INDEX]
        if (item > 0) {
            val landmarks: DoubleArray? = floatArrayToDouble(landmark)
            // 输入图片的宽
            faceunity.fuItemSetParam(item, "input_width", inputWidth.toDouble())
            // 输入图片的高
            faceunity.fuItemSetParam(item, "input_height", inputHeight.toDouble())
            // 输入图片的特征点，75个点
            faceunity.fuItemSetParam(item, "input_face_points", landmarks)
            // 输入图片的 RGBA byte 数组
            faceunity.fuCreateTexForItem(item, "tex_input", input, inputWidth, inputHeight)
        }
    }

    override fun setCartoonFilter(style: Int) {
        if (mCartoonFilterStyle == style) {
            return
        }
        mCartoonFilterStyle = style
        queueEvent(Runnable {
            val isValid = mCartoonFilterStyle > CartoonFilterParam.NO_FILTER
            val item =
                mItemsArray[ITEM_ARRAYS_CARTOON_FILTER_INDEX]
            if (item > 0) {
                if (isValid) {
                    faceunity.fuItemSetParam(item, CartoonFilterParam.STYLE, style.toDouble())
                } else {
                    faceunity.fuDestroyItem(item)
                    mItemsArray[ITEM_ARRAYS_CARTOON_FILTER_INDEX] = 0
                }
            } else if (isValid) {
                mFuItemHandler?.sendEmptyMessage(ITEM_ARRAYS_CARTOON_FILTER_INDEX)
            }
        })
    }

    override fun onLightMakeupCombinationSelected(makeupItems: List<LightMakeupItem>) {
        val keySet = mLightMakeupItemMap.keys
        for (integer in keySet) {
            queueEvent(Runnable {
                val item =
                    mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX]
                if (item > 0) {
                    faceunity.fuItemSetParam(
                        item,
                        MakeupParamHelper.getMakeupTextureKeyByType(integer),
                        0.0
                    )
                }
            })
        }
        mLightMakeupItemMap.clear()

        if (makeupItems != null && makeupItems.size > 0) {
            var i = 0
            val size = makeupItems.size
            while (i < size) {
                val makeupItem = makeupItems[i]
                onLightMakeupSelected(makeupItem, makeupItem.level)
                i++
            }
        } else {
            queueEvent(Runnable {
                val item =
                    mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX]
                if (item > 0) {
                    faceunity.fuItemSetParam(item, MakeupParamHelper.MakeupParam.IS_MAKEUP_ON, 0.0)
                }
            })
        }
    }
    private fun onLightMakeupSelected(makeupItem: LightMakeupItem, level: Float) {
        val type: Int = makeupItem.type
        val item = mLightMakeupItemMap[type]
        if (item != null) {
            item.level = level
        } else {
            // 复制一份
            mLightMakeupItemMap[type] = makeupItem.cloneSelf()
        }
        if (mFuItemHandler == null) {
            queueEvent(Runnable {
                mFuItemHandler!!.sendMessage(
                    Message.obtain(
                        mFuItemHandler,
                        ITEM_ARRAYS_LIGHT_MAKEUP_INDEX,
                        makeupItem
                    )
                )
            })
        } else {
            mFuItemHandler!!.sendMessage(
                Message.obtain(
                    mFuItemHandler,
                    ITEM_ARRAYS_LIGHT_MAKEUP_INDEX,
                    makeupItem
                )
            )
        }
    }

    override fun onLightMakeupItemLevelChanged(makeupItem: LightMakeupItem) {
        val type: Int = makeupItem.type
        val item = mLightMakeupItemMap[type]
        if (item != null) {
            item.level = makeupItem.level
        } else {
            mLightMakeupItemMap[type] = makeupItem.cloneSelf()
        }
        val level: Float = makeupItem.level
        queueEvent(Runnable {
            val item = mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX]
            if (item > 0) {
                faceunity.fuItemSetParam(
                    item,
                    MakeupParamHelper.getMakeupTextureKeyByType(type),
                    level.toDouble()
                )
            }
        })
    }

    override fun selectMakeup(makeupEntity: MakeupEntity, paramMap: Map<String, Any>) {
        mMakeupParams.clear()
        if (paramMap != null) {
            mMakeupParams.putAll(paramMap)
        }
        if (mFuItemHandler != null) {
            mFuItemHandler!!.removeMessages(ITEM_ARRAYS_FACE_MAKEUP_INDEX)
            Message.obtain(
                mFuItemHandler,
                ITEM_ARRAYS_FACE_MAKEUP_INDEX,
                makeupEntity
            ).sendToTarget()
        } else {
            queueEvent(Runnable {
                mFuItemHandler!!.removeMessages(ITEM_ARRAYS_FACE_MAKEUP_INDEX)
                Message.obtain(
                    mFuItemHandler,
                    ITEM_ARRAYS_FACE_MAKEUP_INDEX,
                    makeupEntity
                ).sendToTarget()
            })
        }
    }

    override fun setMakeupItemParam(paramMap: Map<String, Any>) {
        if (paramMap == null) return


        mMakeupParams.putAll(paramMap)
        queueEvent(Runnable {
            val makeupHandle =
                mItemsArray[ITEM_ARRAYS_FACE_MAKEUP_INDEX]
            if (makeupHandle <= 0) {
                return@Runnable
            }
            val entries = paramMap.entries
            faceunity.fuItemSetParam(
                makeupHandle,
                MakeupParamHelper.MakeupParam.IS_CLEAR_MAKEUP,
                0.0
            )
            for ((key, value) in entries) {
                if (value is String && value.endsWith(".bundle")) {
                    val newItemHandle: Int = loadItem(
                        context,
                        value
                    )
                    if (mMakeupItemHandleMap.containsKey(key)) {
                        val oldItemHandle = mMakeupItemHandleMap[key]!!
                        if (oldItemHandle > 0) {
                            faceunity.fuUnBindItems(makeupHandle, intArrayOf(oldItemHandle))
                            faceunity.fuDestroyItem(oldItemHandle)

                        }
                    }
                    if (newItemHandle > 0) {
                        faceunity.fuBindItems(makeupHandle, intArrayOf(newItemHandle))
                        mMakeupItemHandleMap[key] = newItemHandle
                    }
                } else if (value is DoubleArray) {
                    faceunity.fuItemSetParam(makeupHandle, key, value)
                } else if (value is Double) {
                    faceunity.fuItemSetParam(makeupHandle, key, value)
                }
            }
        })
    }

    override fun setMakeupItemIntensity(name: String, density: Double) {
        mMakeupParams[name] = density
        queueEvent(Runnable {
            val makeupHandle =
                mItemsArray[ITEM_ARRAYS_FACE_MAKEUP_INDEX]
            if (makeupHandle > 0) {
                faceunity.fuItemSetParam(makeupHandle, name, density)
            }
        })
    }

    override fun setMakeupItemColor(name: String, colors: DoubleArray) {
        if (colors == null) return
        mMakeupParams[name] = colors
        queueEvent(Runnable {
            val makeupHandle =
                mItemsArray[ITEM_ARRAYS_FACE_MAKEUP_INDEX]
            if (makeupHandle > 0) {
                faceunity.fuItemSetParam(makeupHandle, name, colors)
            }
        })
    }

    override fun setBodySlimIntensity(intensity: Float) {
        queueEvent(Runnable {
            mBodySlimStrength = intensity
            val itemBody = mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY]
            if (itemBody > 0) {
                faceunity.fuItemSetParam(
                    itemBody,
                    BodySlimParam.BODY_SLIM_STRENGTH,
                    intensity.toDouble()
                )
            }
        })
    }

    override fun setLegSlimIntensity(intensity: Float) {
        queueEvent(Runnable {
            mLegSlimStrength = intensity
            val itemBody = mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY]
            if (itemBody > 0) {
                faceunity.fuItemSetParam(
                    itemBody,
                    BodySlimParam.LEG_SLIM_STRENGTH,
                    intensity.toDouble()
                )
            }
        })
    }

    override fun setWaistSlimIntensity(intensity: Float) {
        queueEvent(Runnable {
            mWaistSlimStrength = intensity
            val itemBody = mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY]
            if (itemBody > 0) {
                faceunity.fuItemSetParam(
                    itemBody,
                    BodySlimParam.WAIST_SLIM_STRENGTH,
                    intensity.toDouble()
                )
            }
        })
    }

    override fun setShoulderSlimIntensity(intensity: Float) {
        queueEvent(Runnable {
            mShoulderSlimStrength = intensity
            val itemBody = mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY]
            if (itemBody > 0) {
                faceunity.fuItemSetParam(
                    itemBody,
                    BodySlimParam.SHOULDER_SLIM_STRENGTH,
                    intensity.toDouble()
                )
            }
        })
    }

    override fun setHipSlimIntensity(intensity: Float) {
        queueEvent(Runnable {
            mHipSlimStrength = intensity
            val itemBody = mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY]
            if (itemBody > 0) {
                faceunity.fuItemSetParam(
                    itemBody,
                    BodySlimParam.HIP_SLIM_STRENGTH,
                    intensity.toDouble()
                )
            }
        })
    }

    override fun setHeadSlimIntensity(intensity: Float) {
        queueEvent(Runnable {
            mHeadSlimStrength = intensity
            if (mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY] > 0) {
                faceunity.fuItemSetParam(
                    mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY],
                    BodySlimParam.HEAD_SLIM,
                    intensity.toDouble()
                )
            }
        })
    }

    override fun setLegThinSlimIntensity(intensity: Float) {
        queueEvent(Runnable {
            mLegThinSlimStrength = intensity
            if (mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY] > 0) {
                faceunity.fuItemSetParam(
                    mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY],
                    BodySlimParam.LEG_SLIM,
                    intensity.toDouble()
                )
            }
        })
    }

    override fun setRemovePouchStrength(strength: Float) {
        sMicroPouch = strength;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun setRemoveNasolabialFoldsStrength(strength: Float) {
        sMicroNasolabialFolds = strength;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun setSmileIntensity(intensity: Float) {
        sMicroSmile = intensity;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun setCanthusIntensity(intensity: Float) {
        sMicroCanthus = intensity;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun setPhiltrumIntensity(intensity: Float) {
        sMicroPhiltrum = intensity;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun setLongNoseIntensity(intensity: Float) {
        sMicroLongNose = intensity;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun setEyeSpaceIntensity(intensity: Float) {
        sMicroEyeSpace = intensity;
        mIsNeedUpdateFaceBeauty = true;
    }

    override fun setEyeRotateIntensity(intensity: Float) {
        sMicroEyeRotate = intensity;
        mIsNeedUpdateFaceBeauty = true;
    }

    private fun setBeautyBodyOrientation() {
        val itemBody = mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY]
        if (itemBody > 0) {
            val bodyOrientation = calculateRotationMode()
            faceunity.fuItemSetParam(
                itemBody,
                BodySlimParam.ORIENTATION,
                bodyOrientation.toDouble()
            )
        }
    }

    private fun calculateRotModeLagacy(): Int {
        return if (mInputOrientation == 270) {
            if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                mDeviceOrientation / 90
            } else {
                (mDeviceOrientation - 180) / 90
            }
        } else {
            if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                (mDeviceOrientation + 180) / 90
            } else {
                mDeviceOrientation / 90
            }
        }
    }

    private fun floatArrayToDouble(input: FloatArray): DoubleArray? {
        if (input == null) {
            return null
        }
        val output = DoubleArray(input.size)
        for (i in input.indices) {
            output[i] = input[i].toDouble()
        }
        return output
    }


    /*
    设置对道具相应的参数
     */
    private fun updateEffectItemParams(effect: FuEffect?, itemHandle: Int) {
        mRotationMode = calculateRotationMode()
        when(mExternalInputType){
            EXTERNAL_INPUT_TYPE_IMAGE -> {
                faceunity.fuItemSetParam(itemHandle, "isAndroid", 0.0)
            }
            EXTERNAL_INPUT_TYPE_VIDEO -> {
                faceunity.fuItemSetParam(
                    itemHandle,
                    "isAndroid",
                    if (mIsSystemCameraRecord) 1.0 else 0.0
                )
            }
            else ->{
                faceunity.fuItemSetParam(itemHandle, "isAndroid", 1.0)
            }
        }
        val effectType = effect?.type
        val back = if (mCameraFacing == Camera.CameraInfo.CAMERA_FACING_BACK) 1 else 0
        when(effectType){
            FuEffect.EFFECT_TYPE_STICKER, FuEffect.EFFECT_TYPE_EXPRESSION_RECOGNITION -> {
                faceunity.fuItemSetParam(
                    itemHandle,
                    "rotationAngle",
                    mRotationMode.times(90).toDouble()
                )
            }
            FuEffect.EFFECT_TYPE_ANIMOJI, FuEffect.EFFECT_TYPE_PORTRAIT_DRIVE -> {
                faceunity.fuItemSetParam(itemHandle, "is3DFlipH", back.toDouble())
                faceunity.fuItemSetParam(itemHandle, "isFlipExpr", back.toDouble())
                //这两句代码用于识别人脸默认方向的修改，主要针对animoji道具的切换摄像头倒置问题
                faceunity.fuItemSetParam(itemHandle, "camera_change", 1.0)
            }
            FuEffect.EFFECT_TYPE_GESTURE_RECOGNITION -> {
                //loc_y_flip与loc_x_flip 参数是用于对手势识别道具的镜像

                //loc_y_flip与loc_x_flip 参数是用于对手势识别道具的镜像
                faceunity.fuItemSetParam(itemHandle, "is3DFlipH", back.toDouble())
                faceunity.fuItemSetParam(itemHandle, "loc_y_flip", back.toDouble())
                faceunity.fuItemSetParam(itemHandle, "loc_x_flip", back.toDouble())
            }
        }
        setEffectRotationMode(effect, itemHandle)
        if (effectType == FuEffect.EFFECT_TYPE_ANIMOJI){
            // 镜像跟踪（位移和旋转）

            // 镜像跟踪（位移和旋转）
            faceunity.fuItemSetParam(itemHandle, "isFlipTrack", back.toDouble())
            // 镜像灯光
            // 镜像灯光
            faceunity.fuItemSetParam(itemHandle, "isFlipLight ", back.toDouble())
            // 设置 Animoji 跟随人脸
            // 设置 Animoji 跟随人脸
            faceunity.fuItemSetParam(
                itemHandle,
                "{\"thing\":\"<global>\",\"param\":\"follow\"}",
                1.0
            )
        }
        setMaxFaces(effect?.maxFace!!.or(0))
    }

    private fun setEffectRotationMode(effect: FuEffect?, itemHandle: Int){
        val rotMode = if (effect?.type === FuEffect.EFFECT_TYPE_GESTURE_RECOGNITION && effect.bundleName.startsWith(
                "ctrl"
            )) {
            calculateRotModeLagacy()
        } else {
            mRotationMode
        }
        faceunity.fuItemSetParam(itemHandle, "rotMode", rotMode.toDouble())
        faceunity.fuItemSetParam(itemHandle, "rotationMode", rotMode.toDouble())
    }


    //-------------————FPS
    //--------------------------------------FPS（FPS相关定义）----------------------------------------
    private var NANO_IN_ONE_MILLI_SECOND: Int = 1000000
    private var NANO_IN_ONE_NANO_SECOND = 1000000000
    private var TIME = 10
    private var mCurrentFrameCnt = 0
    private var mLastOneHundredFrameTimeStamp: Long = 0
    private var mOneHundredFrameFUTime: Long = 0
    private var mNeedBenchmark = true
    private var mFuCallStartTime: Long = 0

    private var onFuDebugListener: OnFuDebugListener? = null

    interface OnFuDebugListener{
        fun onFpsChange(fps: Double, renderTime: Double)
    }

    private fun benchmarkFPS(){
        if (!mNeedBenchmark) return
        if (++mCurrentFrameCnt == TIME){
            mCurrentFrameCnt = 0
            val fps = TIME.toFloat().times(NANO_IN_ONE_NANO_SECOND).div(System.nanoTime() - mLastOneHundredFrameTimeStamp)
            val renderTime = mOneHundredFrameFUTime.toFloat().div(TIME).div(NANO_IN_ONE_MILLI_SECOND)
            mLastOneHundredFrameTimeStamp = System.nanoTime()
            mOneHundredFrameFUTime = 0
            onFuDebugListener?.onFpsChange(fps.toDouble(), renderTime.toDouble())
        }

    }

    //--------------------------------------FaceUnitySystemError（faceunity错误信息回调相关定义）----------------------------------------
    interface OnSystemErrorListener {
        fun onSystemError(error: String?)
    }

    private var mOnSystemErrorListener: OnSystemErrorListener? = null

    //**************************************人脸识别回调定义
    private var mTrackHumanStatus:Int = -1
    private var mTrackFaceStatus:Int = -1

    interface OnTrackingStatusChangeListener{
        fun onTrackStatusCHanged(type: Int, status: Int)
    }

    private var onTrackingStatusChangeListener: OnTrackingStatusChangeListener? = null


    //---------------------------------------Builder---------------------------

    class Builder(val context: Context) {
        private var createEGLContext = false
        private var effect: Beauty? = null
        private var maxFace: Int = 1
        private var maxHumans: Int = 1
        private var inputTextureType = 0

        private var inputImageFormat = 0
        private var inputOrientation = 270
        private var externalInputType: Int = EXTERNAL_INPUT_TYPE_NONE
        private var isNeedFaceBeauty = true
        private var isNeedAnimoji3D = false
        private var isNeedBeautyHair = false
        private var isNeedPosterFace = false
        private var isNeedBodySlim = false
        private var cameraFacing = Camera.CameraInfo.CAMERA_FACING_FRONT
        private var onBundleLoadCompleteListener: OnBundleLoadCompleteListener? = null
        private var onFUDebugListener: OnFuDebugListener? = null
        private var onTrackingStatusChangedListener: OnTrackingStatusChangeListener? = null
        private var onSystemErrorListener: OnSystemErrorListener? = null
        private var mIsLoadAiGesture = false
        private var mIsLoadAiHumanProcessor = false

        /**
         * 是否需要美颜效果
         *
         * @param needFaceBeauty
         * @return
         */
        fun setNeedFaceBeauty(needFaceBeauty: Boolean): Builder {
            isNeedFaceBeauty = needFaceBeauty
            return this
        }

        /**
         * 识别最大人脸数
         *
         * @param maxFaces
         * @return
         */
        fun setMaxFaces(maxFaces: Int): Builder {
            this.maxFace = maxFaces;
            return this;
        }

        /**
         * 识别最大人体数
         *
         * @param maxHumans
         * @return
         */
        fun maxHumans(maxHumans: Int): Builder {
            this.maxHumans = maxHumans;
            return this

        }

        /**
         * 传入纹理的类型（传入数据没有纹理则无需调用）
         * camera OES纹理：1
         * 普通2D纹理：0
         *
         * @param textureType
         * @return
         */
        fun inputTextureType(textureType: Int): Builder {
            inputTextureType = textureType
            return this
        }

        /**
         * 外部输入的类型，INPUT_TYPE_IMAGE or INPUT_TYPE_VIDEO
         *
         * @param externalInputType
         * @return
         */
        fun setExternalInputType(externalInputType: Int): Builder {
            this.externalInputType = externalInputType
            return this
        }


        /**
         * 输入的画面数据方向
         *
         * @param inputOrientation
         * @return
         */
        fun inputImageOrientation(inputOrientation: Int): Builder {
            this.inputOrientation = inputOrientation
            return this
        }

        /**
         * 设置SDK使用错误回调
         *
         * @param onSystemErrorListener
         * @return
         */
        fun setOnSystemErrorListener(onSystemErrorListener:OnSystemErrorListener): Builder {
            this.onSystemErrorListener = onSystemErrorListener
            return this
        }

        fun build(): FURendererKt {
            val fuRenderer: FURendererKt = FURendererKt(context, createEGLContext)
            fuRenderer.mMaxFaces = maxFace
            fuRenderer.mMaxHumans = maxHumans
            fuRenderer.mInputTextureType = inputTextureType
            fuRenderer.mInputImageFormat = inputImageFormat
            fuRenderer.mInputOrientation = inputOrientation
            fuRenderer.mExternalInputType = externalInputType
            fuRenderer.isNeedFaceBeauty = isNeedFaceBeauty
            fuRenderer.isNeedBodySlim = isNeedBodySlim
            fuRenderer.isNeedAnimoji3D = isNeedAnimoji3D
            fuRenderer.isNeedBeautyHair = isNeedBeautyHair
            fuRenderer.isNeedPosterFace = isNeedPosterFace
            fuRenderer.mCameraFacing = cameraFacing
            fuRenderer.onTrackingStatusChangeListener = onTrackingStatusChangedListener
            fuRenderer.mOnSystemErrorListener = onSystemErrorListener
            fuRenderer.mOnBundleLoadCompleteListener = onBundleLoadCompleteListener
            fuRenderer.mIsLoadAiGesture = mIsLoadAiGesture
            fuRenderer.mIsLoadAiHumanProcessor = mIsLoadAiHumanProcessor
            return fuRenderer
        }


    }




    inner class FuItemHandler(looper: Looper) : Handler(looper){
        override fun handleMessage(msg: Message) {
            when(msg.what){
                ITEM_ARRAYS_EFFECT_INDEX -> {
                    val effect = msg.obj as? FuEffect
                    val isNone = effect?.type == FuEffect.EFFECT_TYPE_NONE
                    val itemEffect = if (isNone) 0 else loadItem(context, effect?.bundlePath)
                    if (!isNone && itemEffect <= 0) return
                    queueEvent(Thread {
                        if (mItemsArray[ITEM_ARRAYS_EFFECT_INDEX] > 0) {
                            faceunity.fuDestroyItem(mItemsArray[ITEM_ARRAYS_EFFECT_INDEX])
                            mItemsArray[ITEM_ARRAYS_EFFECT_INDEX] = 0
                        }
                        if (itemEffect > 0) {
                            updateEffectItemParams(effect, itemEffect)
                        }
                        mItemsArray[ITEM_ARRAYS_EFFECT_INDEX] = itemEffect
                    })
                }
                ITEM_ARRAYS_FACE_BEAUTY_INDEX -> {
                    val itemBeauty = loadItem(context, BUNDLE_FACE_BEAUTIFICATION)
                    if (itemBeauty <= 0) return
                    queueEvent(Thread {
                        if (mItemsArray[ITEM_ARRAYS_FACE_BEAUTY_INDEX] > 0) {
                            faceunity.fuDestroyItem(mItemsArray[ITEM_ARRAYS_FACE_BEAUTY_INDEX])
                            mItemsArray[ITEM_ARRAYS_FACE_BEAUTY_INDEX] = 0
                        }
                        mItemsArray[ITEM_ARRAYS_FACE_BEAUTY_INDEX] = itemBeauty
                        mIsNeedUpdateFaceBeauty = true
                    })
                }
                ITEM_ARRAYS_LIGHT_MAKEUP_INDEX -> {
                    if (msg.obj !is LightMakeupItem) return
                    val makeupItem = msg.obj as LightMakeupItem
                    val path = makeupItem.path
                    if (mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX] <= 0) {
                        val itemMakeupItem = loadItem(context, BUNDLE_LIGHT_MAKEUP)
                        if (itemMakeupItem <= 0) return else mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX] =
                            itemMakeupItem
                    }
                    if (path.isNotEmpty()) {
                        var textureImage: MakeupParamHelper.TextureImage? = null
                        var lipStickColor: DoubleArray? = DoubleArray(0)
                        if (makeupItem.type == LightMakeupItem.FACE_MAKEUP_TYPE_LIPSTICK) {
                            lipStickColor = MakeupParamHelper.readRgbaColor(context, path)
                        } else {
                            textureImage = MakeupParamHelper.createTextureImage(context, path)
                        }

                        queueEvent(Thread {
                            val itemHandle = mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX]
                            faceunity.fuItemSetParam(
                                itemHandle,
                                MakeupParamHelper.MakeupParam.IS_MAKEUP_ON,
                                1.0
                            )
                            faceunity.fuItemSetParam(
                                itemHandle,
                                MakeupParamHelper.MakeupParam.MAKEUP_INTENSITY,
                                1.0
                            )
                            faceunity.fuItemSetParam(
                                itemHandle,
                                MakeupParamHelper.MakeupParam.REVERSE_ALPHA,
                                1.0
                            )
                            faceunity.fuItemSetParam(
                                itemHandle, MakeupParamHelper.getMakeupTextureKeyByType(
                                    makeupItem.type
                                ), makeupItem.level.toDouble()
                            )
                            if (lipStickColor != null) {
                                if (makeupItem.type == LightMakeupItem.FACE_MAKEUP_TYPE_LIPSTICK) {
                                    faceunity.fuItemSetParam(
                                        itemHandle,
                                        MakeupParamHelper.MakeupParam.MAKEUP_LIP_COLOR,
                                        lipStickColor
                                    )
                                    faceunity.fuItemSetParam(
                                        itemHandle,
                                        MakeupParamHelper.MakeupParam.MAKEUP_LIP_MASK,
                                        1.0
                                    )
                                }
                            } else {
                                faceunity.fuItemSetParam(
                                    itemHandle,
                                    MakeupParamHelper.MakeupParam.MAKEUP_INTENSITY_LIP,
                                    0.0
                                )
                            }
                            if (textureImage != null) {
                                faceunity.fuCreateTexForItem(
                                    itemHandle, MakeupParamHelper.getMakeupTextureKeyByType(
                                        makeupItem.type
                                    ), textureImage.bytes, textureImage.width, textureImage.height
                                )
                            }
                        })
                    } else {
                        queueEvent(Thread {
                            if (mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX] > 0) {
                                faceunity.fuItemSetParam(
                                    mItemsArray[ITEM_ARRAYS_LIGHT_MAKEUP_INDEX],
                                    MakeupParamHelper.getMakeupTextureKeyByType(
                                        makeupItem.type
                                    ),
                                    0.0
                                )
                            }
                        })
                    }

                }
                ITEM_ARRAYS_FACE_MAKEUP_INDEX -> {
                    if (msg.obj == null) return
                    var itemMakeup = 0
                    if (mItemsArray[ITEM_ARRAYS_FACE_MAKEUP_INDEX] <= 0) {
                        itemMakeup = loadItem(context, BUNDLE_FACE_MAKEUP)
                        if (itemMakeup <= 0) return
                        mItemsArray[ITEM_ARRAYS_FACE_MAKEUP_INDEX] = itemMakeup
                    } else {
                        itemMakeup = mItemsArray[ITEM_ARRAYS_FACE_MAKEUP_INDEX]
                    }
                    val makeupEntity: MakeupEntity =
                        (if (msg.obj is MakeupEntity) msg.obj as MakeupEntity else null) ?: return
                    makeupEntity.itemHandle = loadItem(context, makeupEntity.bundlePath)
                    val makeupItemHandleMap: MutableMap<String, Int> = HashMap(16)
                    mMakeupParams.forEach {
                        if (it.value is String && (it.value as String).endsWith(".bundle")) {
                            val handle = loadItem(context, it.value as String)
                            if (handle > 0) makeupItemHandleMap[it.key] = handle
                        }
                    }

                    queueEvent(Thread {
                        var size = mMakeupItemHandleMap.size
                        if (size > 0) {
                            faceunity.fuUnBindItems(
                                itemMakeup,
                                mMakeupItemHandleMap.values.toIntArray()
                            )
                            makeupItemHandleMap.forEach {
                                faceunity.fuDestroyItem(it.value.toInt())
                            }
                            makeupItemHandleMap.clear()
                        }
                        if (mMakeupEntity != null) {
                            val itemHandle = mMakeupEntity!!.itemHandle
                            if (itemHandle > 0) {
                                faceunity.fuUnBindItems(itemMakeup, IntArray(1) { itemHandle })
                                faceunity.fuDestroyItem(itemHandle)
                                mMakeupEntity!!.itemHandle = 0
                            }
                        }
                        if (makeupEntity.itemHandle > 0) {
                            faceunity.fuBindItems(
                                itemMakeup,
                                IntArray(1) { makeupEntity.itemHandle })
                        }
                        size = makeupItemHandleMap.size
                        if (size > 0) {
                            val itemHandles = IntArray(size)
                            faceunity.fuBindItems(
                                itemMakeup,
                                makeupItemHandleMap.values.toIntArray()
                            )
                            mMakeupItemHandleMap.putAll(makeupItemHandleMap)
                        }

                        val makeupParamEntries = mMakeupParams.entries
                        makeupParamEntries.forEach {
                            if (it.value is DoubleArray) {
                                faceunity.fuItemSetParam(
                                    itemMakeup,
                                    it.key,
                                    (it.value as DoubleArray)
                                )
                            } else if (it.value is Double) {
                                faceunity.fuItemSetParam(itemMakeup, it.key, (it.value as Double))
                            }
                        }

                        if (mExternalInputType == EXTERNAL_INPUT_TYPE_IMAGE || mExternalInputType == EXTERNAL_INPUT_TYPE_VIDEO) {
                            mIsMakeupFlipPoints = !mIsMakeupFlipPoints
                        }
                        faceunity.fuItemSetParam(
                            itemMakeup, MakeupParamHelper.MakeupParam.IS_FLIP_POINTS,
                            if (mIsMakeupFlipPoints) 1.0 else 0.0
                        )
                        faceunity.fuItemSetParam(
                            itemMakeup,
                            MakeupParamHelper.MakeupParam.MAKEUP_LIP_MASK,
                            1.0
                        )
                        faceunity.fuItemSetParam(
                            itemMakeup,
                            MakeupParamHelper.MakeupParam.MAKEUP_INTENSITY,
                            1.0
                        )
                        faceunity.fuItemSetParam(
                            itemMakeup,
                            MakeupParamHelper.MakeupParam.IS_CLEAR_MAKEUP,
                            1.0
                        )
                        mMakeupEntity = makeupEntity

                    })


                }
                ITEM_ARRAYS_BEAUTY_HAIR_INDEX -> {
                    var itemHandle = if (mHairColorType == HAIR_NORMAL) {
                        loadItem(context, BUNDLE_HAIR_NORMAL)
                    } else if (mHairColorType == HAIR_GRADIENT) {
                        loadItem(context, BUNDLE_HAIR_GRADIENT)
                    } else {
                        0
                    }
                    if (itemHandle <= 0) return
                    queueEvent(Thread {
                        if (mItemsArray[ITEM_ARRAYS_BEAUTY_HAIR_INDEX] > 0) {
                            faceunity.fuDestroyItem(mItemsArray[ITEM_ARRAYS_BEAUTY_HAIR_INDEX])
                            mItemsArray[ITEM_ARRAYS_BEAUTY_HAIR_INDEX] = 0
                        }
                        faceunity.fuItemSetParam(
                            itemHandle,
                            HairParam.INDEX,
                            mHairColorIndex.toDouble()
                        )
                        faceunity.fuItemSetParam(
                            itemHandle,
                            HairParam.STRENGTH,
                            mHairColorStrength.toDouble()
                        )
                        mItemsArray[ITEM_ARRAYS_BEAUTY_HAIR_INDEX] = itemHandle
                    })

                }
                ITEM_ARRAYS_CARTOON_FILTER_INDEX -> {
                    val itemCartoonFilter = loadItem(context, BUNDLE_CARTOON_FILTER)
                    if (itemCartoonFilter <= 0) return
                    queueEvent(Thread {
                        faceunity.fuItemSetParam(
                            itemCartoonFilter,
                            CartoonFilterParam.STYLE,
                            mCartoonFilterStyle.toDouble()
                        )
                        faceunity.fuItemSetParam(
                            itemCartoonFilter,
                            CartoonFilterParam.GLVER,
                            GlUtil.getGlMajorVersion().toDouble()
                        )
                        mItemsArray[ITEM_ARRAYS_CARTOON_FILTER_INDEX] = itemCartoonFilter
                    })
                }

                ITEM_ARRAYS_BEAUTIFY_BODY -> {
                    val itemBeautifyBody = loadItem(context, BUNDLE_BEAUTIFY_BODY)
                    if (itemBeautifyBody <= 0) return

                    queueEvent(Thread {
                        if (mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY] > 0) {
                            faceunity.fuDestroyItem(mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY])
                            mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY] = 0
                        }
                        faceunity.fuItemSetParam(
                            itemBeautifyBody,
                            BodySlimParam.BODY_SLIM_STRENGTH,
                            mBodySlimStrength.toDouble()
                        )
                        faceunity.fuItemSetParam(
                            itemBeautifyBody,
                            BodySlimParam.LEG_SLIM_STRENGTH,
                            mLegSlimStrength.toDouble()
                        )
                        faceunity.fuItemSetParam(
                            itemBeautifyBody,
                            BodySlimParam.WAIST_SLIM_STRENGTH,
                            mWaistSlimStrength.toDouble()
                        )
                        faceunity.fuItemSetParam(
                            itemBeautifyBody,
                            BodySlimParam.SHOULDER_SLIM_STRENGTH,
                            mShoulderSlimStrength.toDouble()
                        )
                        faceunity.fuItemSetParam(
                            itemBeautifyBody,
                            BodySlimParam.HIP_SLIM_STRENGTH,
                            mHipSlimStrength.toDouble()
                        )
                        faceunity.fuItemSetParam(
                            itemBeautifyBody,
                            BodySlimParam.HEAD_SLIM,
                            mHeadSlimStrength.toDouble()
                        )
                        faceunity.fuItemSetParam(
                            itemBeautifyBody,
                            BodySlimParam.LEG_SLIM,
                            mLegThinSlimStrength.toDouble()
                        )
                        faceunity.fuItemSetParam(itemBeautifyBody, BodySlimParam.DEBUG, 0.0)
                        mItemsArray[ITEM_ARRAYS_BEAUTIFY_BODY] = itemBeautifyBody
                        setBeautyBodyOrientation()
                    })
                }
                ITEM_ARRAYS_ABIMOJI_3D_INDEX -> {
                    val itemAnim3D = loadItem(context, BUNDLE_FXAA)
                    if (itemAnim3D <= 0) return
                    queueEvent(Thread {
                        if (mItemsArray[ITEM_ARRAYS_ABIMOJI_3D_INDEX] > 0) {
                            faceunity.fuDestroyItem(mItemsArray[ITEM_ARRAYS_ABIMOJI_3D_INDEX])
                            mItemsArray[ITEM_ARRAYS_ABIMOJI_3D_INDEX] = 0
                        }
                        mItemsArray[ITEM_ARRAYS_ABIMOJI_3D_INDEX] = itemAnim3D
                    })
                }
            }
            mOnBundleLoadCompleteListener?.onBundleLoadComplete(msg.what)
        }
    }
}









































